package com.nc.mem.serial.graph.asm;

import java.lang.reflect.Modifier;

import org.objectweb.asm.Type;

public abstract class FieldInfo implements Comparable<FieldInfo> {

	public final String owner;
	public final Type type;
	public final String name;
	public final long offset;
	public int flags;

	public FieldInfo(final String owner, final String name, final Type type, final long offset, final int flags) {
		super();
		this.owner = owner;
		this.name = name;
		this.type = type;
		this.offset = offset;
		this.flags = flags;
	}

	@Override
	public int compareTo(final FieldInfo o) {
		final long delta = this.offset - o.offset;

		// if (delta == 0) {
		final Class<?> thisType = type();
		final Class<?> otherType = o.type();

		if (thisType.isPrimitive()) {
			return otherType.isPrimitive() ? this.name.compareTo(o.name) : -1;
		}

		if (Iterable.class.isAssignableFrom(thisType)) {
			return Iterable.class.isAssignableFrom(otherType) ? this.name.compareTo(o.name) : 1;
		}

		return Iterable.class.isAssignableFrom(otherType) ? -1 : (int) Math.signum(delta);
		// }
		// return (int) Math.signum(delta);
	}

	public String desc() {
		return type.getDescriptor();
	}

	public String internalName() {
		return type.getInternalName();
	}

	public abstract boolean isCollection();

	public boolean isFinal() {
		return Modifier.isFinal(flags);
	}

	public abstract boolean isMap();

	public abstract boolean isOnlyPayloadCollection();

	public abstract boolean isOnlyPayloadMapKey();

	public final boolean isOnlyPayloadMapKeyVal() {
		return isOnlyPayloadMapKey() && isOnlyPayloadMapVal();
	}

	public abstract boolean isOnlyPayloadMapVal();

	public boolean isPrivate() {
		return Modifier.isPrivate(flags);
	}

	public boolean isTypeFinal() {
		return Modifier.isFinal(type().getModifiers());
	}

	public String name() {
		return name;
	}

	public String owner() {
		return owner;
	}

	public void treatAsPrivate() {
		flags &= ~Modifier.PUBLIC | ~Modifier.PROTECTED;
		flags |= Modifier.PRIVATE;
	}

	public abstract Class<?> type();

	public String typeName() {
		return type().getName();
	}

}